home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1997 February
/
EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso
/
enigma
/
earcd
/
utility
/
utilmisc
/
shutdown.lzh
/
shutdown_5.1
/
src
/
shutdown.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-02
|
13KB
|
545 lines
/*
shutdown.c --- shutdown command.
(c) Copyright 1995 SHW Wabnitz
Written by Bernhard Fastenrath (fasten@shw.com)
This file may be distributed under the terms
of the GNU General Public License.
History:
12-12-95, bf: fflush (stdout) added (for Syslog)
10-30-96, bf: shutdown delay
11-28-96, bf: message format changed
12-03-96, bf: gcc compatibility restored
*/
#if defined (__SASC)
#include <dos.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include "queue/queue.h"
#include "queue/shutdown.h"
#include "shutdown_cmd.h"
#include <shutdownbase.h>
#if defined (__GNUC__)
#include "queue/queue_inline.h"
#elif defined (__SASC)
#include "queue/queue_pragmas.h"
#endif
#if defined (__GNUC__)
#include <shutdown_inline.h>
#elif defined (__SASC)
#include <shutdown_pragma.h>
#endif
#define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
int Unmount (char *filesystem, int mode);
void GoDown (int time);
void CleanUp (char *error);
QMessage *BroadcastShutdownMsg (ULONG status, ULONG time);
struct IntuitionBase *IntuitionBase = NULL;
struct Library *QueueBase = NULL;
struct Library *ShutdownBase = NULL;
struct timerequest *TimerReq = NULL;
struct MsgPort *TimerPort = NULL;
struct MsgPort *ShutdownPort = NULL;
QHandle ShutdownHandle = NULL;
ULONG TimerMask;
ULONG TimerErr = 1;
ULONG ShutdownMask;
ULONG WaitMask;
ULONG QueueSignal, QueueMask;
int point_of_no_return = 0;
char *ShutdownPortname = "Shutdown";
int SpNameLen;
char *CantAllocatePort = "Can't allocate signal or message port.\n";
char *ShutdownCancelled = "shutdown cancelled.\n";
char *OutOfMemory = "Out of memory.\n";
char *SorryTooLate = "Too late to stop shutdown.\n";
int MessageTimedOut = 0;
int HaltFlag = HFLG_HALT;
int SyncTime = 5;
int MaxTime = 60;
int ShutdownTime = 10;
int UseShutdownLibFlag = 0;
int AbortableFlag = 1;
int FastBoot = 0;
int UnmountMode = UMNT_INHIBIT;
int Error;
char *optarg = NULL;
int
getopt (int argc, char *const *argv, const char *opts)
{
static int pos = 0;
char *c;
while (++pos < argc && argv[pos][0] != '-');
if (pos >= argc)
return -1;
if ((c = strchr (opts, (int) argv[pos][1])) == 0)
return (int) '?';
if (*(c+1) != ':')
return (int) *c;
if (strlen (argv[pos]) > 2)
optarg = argv[pos] + 2;
else if (pos+1 < argc)
optarg = argv[pos+1];
else
return (int) '?';
return (int) *c;
}
ULONG
PutAndGet (Message *msg, char *portname)
{
struct MsgPort *prt, *reply_port;
if (!(reply_port = CreateMsgPort ()))
return 1;
msg -> mn_ReplyPort = reply_port;
Forbid ();
if (prt = FindPort (portname))
{
PutMsg (prt, msg);
Permit ();
do
WaitPort (reply_port);
while (!GetMsg (reply_port));
}
else
Permit ();
DeleteMsgPort (reply_port);
return (ULONG) (prt ? 0 : 2);
}
void
CancelRunningShutdown (void)
{
Message *msg;
if (!(msg = AllocMem (sizeof (Message), MEMF_PUBLIC | MEMF_CLEAR)))
CleanUp (OutOfMemory);
switch (PutAndGet (msg, ShutdownPortname))
{
case 0:
if (msg -> mn_Node.ln_Name == (APTR) -1)
CleanUp (SorryTooLate);
CleanUp (ShutdownCancelled);
case 1:
CleanUp (CantAllocatePort);
case 2:
CleanUp ("Shutdown is not running.\n");
}
FreeMem (msg, sizeof (Message));
}
void
CleanUp (char *error)
{
QMessage *msg;
if (error)
printf (error);
if (!TimerErr)
CloseDevice ((struct IORequest *) TimerReq);
if (TimerReq)
DeleteIORequest (TimerReq);
if (TimerPort)
DeleteMsgPort (TimerPort);
if (ShutdownPort)
{
if (ShutdownPort -> mp_Node.ln_Name)
FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
RemPort (ShutdownPort);
DeleteMsgPort (ShutdownPort);
}
if (ShutdownHandle)
{
while (msg = QGetMsg (ShutdownHandle))
QFreeMsg (msg, sizeof (ShutdownMessage));
if (QClose (ShutdownHandle))
{
printf ("Exiting, waiting for replies.\n");
while (QClose (ShutdownHandle) > 0)
{
Delay (50);
while (msg = QGetMsg (ShutdownHandle))
QFreeMsg (msg, sizeof (ShutdownMessage));
}
}
FreeSignal (QueueSignal);
}
if (QueueBase)
CloseLibrary (QueueBase);
if (ShutdownBase)
CloseLibrary (ShutdownBase);
if (IntuitionBase)
CloseLibrary ((struct Library *) IntuitionBase);
exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
int
CancelShutdown (void)
{
if (point_of_no_return)
return 0;
BroadcastShutdownMsg (SHUTDOWN_ABORT, 0);
CleanUp (ShutdownCancelled);
}
QMessage *
GetShutdownMessage (void)
{
QMessage *sm;
for (;;)
{
if (sm = QGetMsg (ShutdownHandle))
break;
if (sm = QAllocMsg (sizeof (ShutdownMessage)))
break;
Delay (50);
}
return sm;
}
QMessage *
BroadcastShutdownMsg (ULONG status, ULONG time)
{
ShutdownMessage *smsg;
QMessage *qmsg;
qmsg = GetShutdownMessage ();
smsg = (ShutdownMessage *) qmsg -> qm_Data;
smsg -> sm_Status = status;
smsg -> sm_TimeLeft = time;
QAddMsg (ShutdownHandle, qmsg);
return qmsg;
}
void
AbortableDelay (int seconds)
{
int abort = 0, sec;
Message *msg;
ULONG mask;
TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
TimerReq -> tr_time.tv_secs = seconds;
TimerReq -> tr_time.tv_micro = 0;
SendIO ((struct IORequest *) TimerReq);
while (1)
{
mask = Wait (WaitMask);
if (mask & ShutdownMask)
{
if (msg = (Message *) GetMsg (ShutdownPort))
{
if (msg -> mn_Node.ln_Pri == 0) /* shutdown cancel request */
{
if (point_of_no_return || AbortableFlag == 0)
msg -> mn_Node.ln_Name = (APTR) -1;
else
abort = 1;
}
else /* shutdown delay request */
{
sec = msg -> mn_Node.ln_Pri;
if (MaxTime > 0)
{
if ((MaxTime -= sec) < 0)
sec += MaxTime;
ShutdownTime += sec;
printf ("Shutdown delayed by %d seconds.\n", sec);
msg -> mn_Node.ln_Pri = sec;
}
else
{
msg -> mn_Node.ln_Name = (APTR) -1;
printf ("Shutdown delay refused.\n");
}
}
ReplyMsg ((struct Message *) msg);
}
}
if (mask & QueueMask)
{
/* Shutdown Queue reply: we aren't really interested
because we take our messages fresh from the reply
list when we need them.
The timer is still running so we just wait some more.
*/
}
if (mask & SIGBREAKF_MASK || abort)
{
if (point_of_no_return)
{
printf (SorryTooLate);
continue;
}
if (!(mask & TimerMask))
AbortIO ((struct IORequest *) TimerReq);
WaitIO ((struct IORequest *) TimerReq);
SetSignal (0L, TimerMask);
if (mask & SIGBREAKF_CTRL_C || abort)
{
if (mask & SIGBREAKF_CTRL_C)
printf ("CTRL-C\n");
CancelShutdown ();
printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
}
if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
{
printf ("CTRL-D\n");
return;
}
if (!FastBoot)
{
FastBoot = 1;
if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
{
printf ("CTRL-E\n");
GoDown (5);
}
if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
{
printf ("CTRL-F\n");
GoDown (0);
}
}
else
return;
}
if (mask & TimerMask) /* done waiting */
return;
}
}
void
GoingDownMessage (int seconds)
{
if (seconds / 3600)
printf ("The system is going down in %d:%.2d hours.\n",
seconds / 3600, (seconds % 3600) / 60);
else if (seconds / 60)
printf ("The system is going down in %d:%.2d minutes.\n",
seconds / 60, seconds % 60);
else
printf ("The system is going down in %d seconds.\n", seconds);
fflush (stdout);
}
int
main (int argc, char *argv[])
{
int shutdown_interval;
int cancel_flag = 0;
int opt, rest;
SetTaskPri (FindTask (0L), 10);
/*** Options ***/
while ((opt = getopt (argc, argv, "cehiM:nNrs:t:SW")) != -1)
switch (opt)
{
case 'M': MaxTime = atoi (optarg); break;
case 'W': UnmountMode = UMNT_READONLY; break;
case 'S': UseShutdownLibFlag = 1; break;
case 'R': UnmountMode = UMNT_REMOUNT; break;
case 'n': AbortableFlag = 0; break;
case 'r': HaltFlag = HFLG_REBOOT; break;
case 'h': HaltFlag = HFLG_HALT; break;
case 'e': HaltFlag = HFLG_EXIT; break;
case 't': ShutdownTime = atoi (optarg); break;
case 's': SyncTime = atoi (optarg); break;
case 'c': cancel_flag = 1; break;
case 'i': ShutdownTime = 0; MaxTime = 0; break;
default:
printf ("Usage: %s [-cehinNrSW] [-t <time>] [-M <max. time>] [-s <sync time>].\n", argv[0]);
exit (EXIT_FAILURE);
}
/*** Libraries ***/
if (HaltFlag)
IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
if (!(QueueBase = OpenLibrary ("queue.library", 3)))
CleanUp ("Failed to open queue.library.\n");
if (UseShutdownLibFlag)
{
if (!(ShutdownBase = OpenLibrary ("shutdown.library", 2)))
CleanUp ("Failed to open shutdown.library.\n");
}
/*** Cancel shutdown ***/
if (cancel_flag)
CancelRunningShutdown ();
/*** Remount ***/
if (UnmountMode == UMNT_REMOUNT)
{
Unmount (NULL, UnmountMode);
CleanUp ("Filesystems remounted.\n");
}
/*** Shutdown queue ***/
if ((QueueSignal = AllocSignal (-1)) == -1)
CleanUp (CantAllocatePort);
QueueMask = 1 << QueueSignal;
if (!(ShutdownHandle = QOpen ("shutdown", QMODE_SEND, QueueSignal)))
{
FreeSignal (QueueSignal);
CleanUp ("Failed to open shutdown queue.\n");
}
/**** Timer device ***/
if (!(TimerPort = CreateMsgPort ()))
CleanUp (CantAllocatePort);
if (!(TimerReq = (struct timerequest *)
CreateIORequest (TimerPort, sizeof (struct timerequest))))
CleanUp (OutOfMemory);
if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
CleanUp ("Can't open timer device.\n");
TimerMask = 1 << TimerPort -> mp_SigBit;
/*** Don't start shutdown twice ***/
Forbid ();
if (FindPort (ShutdownPortname))
{
Permit ();
CleanUp ("Shutdown is already running.\n");
}
Permit ();
/*** Named message port ***/
if (!(ShutdownPort = CreateMsgPort ()))
CleanUp (CantAllocatePort);
if (!(ShutdownPort -> mp_Node.ln_Name =
AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
CleanUp (OutOfMemory);
bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
ShutdownPort -> mp_Node.ln_Pri = 0;
AddPort (ShutdownPort);
ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
/*** Shutdown interval loop ***/
WaitMask = QueueMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
while (ShutdownTime >= 10)
{
GoingDownMessage (ShutdownTime);
BroadcastShutdownMsg (SHUTDOWN_WARN, ShutdownTime);
shutdown_interval = ShutdownTime / 3;
ShutdownTime -= shutdown_interval;
if (rest = ShutdownTime % 5)
{
shutdown_interval += rest;
ShutdownTime -= rest;
}
AbortableDelay (shutdown_interval);
}
GoDown (ShutdownTime);
}
void
GoDown (int time)
{
struct EasyStruct es = {
sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
};
QMessage *smo, *smi;
ULONG mask;
if (UseShutdownLibFlag)
{
Shutdown (SHUTDOWN_EXTERN);
}
if (time)
{
/* last warning */
GoingDownMessage (time);
BroadcastShutdownMsg (SHUTDOWN_NOW, time);
AbortableDelay (time);
/* too late for writing */
BroadcastShutdownMsg (SHUTDOWN_UMOUNT, 0);
}
point_of_no_return = 1;
printf ("The system is going down, unmounting filesystems.\n");
fflush (stdout);
Unmount (NULL, UnmountMode);
AbortableDelay (SyncTime);
/*** all done, who turns off the light? ***/
if (time && HaltFlag != HFLG_EXIT)
{
smo = BroadcastShutdownMsg (SHUTDOWN_HALT, 0);
TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
TimerReq -> tr_time.tv_secs = 5;
TimerReq -> tr_time.tv_micro = 0;
SendIO ((struct IORequest *) TimerReq);
for (;;) /*** Wait for the last broadcast to be replied ***/
{
mask = Wait (TimerMask | QueueMask);
if (mask & QueueMask)
while (smi = QGetMsg (ShutdownHandle))
{
if (smi == smo)
mask |= TimerMask;
QFreeMsg (smi, sizeof (ShutdownMessage));
}
if (mask & TimerMask)
break;
}
}
switch (HaltFlag)
{
case HFLG_HALT:
printf ("The system is halted.\n");
if (IntuitionBase)
BuildEasyRequest (NULL, &es, NULL);
Delay (10); /* wait 0.5 seconds */
Disable ();
while (1);
case HFLG_REBOOT:
ColdReboot ();
case HFLG_EXIT:
CleanUp ("Done.\n");
}
}